﻿using SoundEngine3.DspPlugins.Meta;
using ZquenceStudio3Host.DspHost;
using ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer.Engine;
using ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer.Engine.Modules.Container;
using ZquenceStudio3Host.Graphics;
using ZquenceStudio3Host.Graphics.Components;
using ZquenceStudio3Host.Graphics.Components.Interfaces;
using ZquenceStudio3Host.Graphics.EntityProperties;
using ZquenceStudio3Host.Graphics.GUI;

namespace DefaultDspPlugins.UI.Common.Modulizer.Engine.GUIv2.Controls
{
    public abstract class BaseModulizerControl : Panel, IDspControl
    {
        private UndoRedoDspPluginInstance mControlledBy;
        private ParameterProperties mParameter;
        private BaseModule mModule;
        private double mValue;
        private double mMaxValue;
        private double mMinValue;
        private int mReadyParameterIndex = -1;
        private bool mDisableEvents;

        public ParameterProperties CurrentParameter { get { return mParameter; } }

        public double Value
        {
            get
            {
                return mValue;
            }
            set
            {
                if (mValue != value)
                {
                    mValue = value;
                    OnValueChanged?.Invoke(this, value);
                    UpdatePosition();
                }
            }
        }

        public double MaxValue
        {
            get
            {
                return mMaxValue;
            }

            set
            {
                if (mMaxValue != value)
                {
                    mMaxValue = value;
                    UpdatePosition();
                }
            }
        }

        public double MinValue
        {
            get
            {
                return mMinValue;
            }

            set
            {
                if (mMinValue != value)
                {
                    mMinValue = value;
                    UpdatePosition();
                }
            }
        }

        internal void UpdateParameter()
        {
            mDisableEvents = true;
            MinValue = mParameter.MinValue;
            MaxValue = mParameter.MaxValue;
            Value = mParameter.RawValue;
            mDisableEvents = false;
            UpdatePosition();
        }

        protected BaseModulizerControl(BasicGuiManager engineCore) : base(engineCore)
        {

        }

        private void UpdatePosition()
        {
            if (!mDisableEvents)
            {
                OnValueUpdated();

                var parameter = mParameter;
                if (parameter != null && parameter.RawValue != Value)
                {
                    parameter.RawValue = Value;
                }
            }
        }

        protected abstract void OnValueUpdated();

        protected void MouseBeginDown()
        {
            if (mControlledBy != null)
            {
                mControlledBy.MouseDown();
                mControlledBy.ChangedByUser = true;
            }
        }

        protected void MouseEndDown()
        {
            if (mControlledBy != null)
            {
                mControlledBy.ChangedByUser = false;
            }
        }

        protected void MouseBeginMove()
        {
            if (mControlledBy != null)
            {
                mControlledBy.ChangedByUser = true;
            }
        }

        protected void MouseEndMove()
        {
            if (mControlledBy != null)
            {
                mControlledBy.ChangedByUser = false;
            }
        }

        protected void MouseUp()
        {
            mControlledBy?.MouseUp();
        }

        public event EventOnValueChanged OnValueChanged;

        public void SetParameter(ParameterProperties parameter, UndoRedoDspPluginInstance controlledBy, BaseModule customModule)
        {
            if (mParameter != null)
            {
                mParameter.OnValueChanged -= MParameter_OnValueChanged;
                mModule = null;
            }

            mParameter = parameter;

            mControlledBy = controlledBy;

            if (parameter != null)
            {
                // Get module.
                if (customModule == null)
                {
                    if (parameter is ModuleParameter)
                    {
                        ModuleParameter moduleParameter = parameter as ModuleParameter;
                        mModule = moduleParameter.Module;
                    }
                }
                else
                {
                    mModule = customModule;
                }

                if (mReadyParameterIndex > -1)
                {
                    int tmpValue = mReadyParameterIndex;
                    mReadyParameterIndex = -1;
                    BaseObject_Set_Dimensionprocent(this, tmpValue);
                }
                else
                {
                    DialButton_OnDialValueChanged(null, mParameter.RawValue);

                    UpdateParameter();

                    mParameter.OnValueChanged += MParameter_OnValueChanged;
                }
            }

            OnParameterChanged();
        }

        protected virtual void OnParameterChanged()
        {

        }

        private void MParameter_OnValueChanged(ParameterProperties obj)
        {
            if (Value != obj.RawValue)
            {
                Value = obj.RawValue;
                DialButton_OnDialValueChanged(null, obj.RawValue);
            }
        }

        void DialButton_OnDialValueChanged(object sender, double value)
        {
            if (mParameter.RawValue != value)
            {
                mParameter.RawValue = value;
            }

            int value_limitDecimal = (int)(value * 100);

            string str_value = (value_limitDecimal / 100.0f).ToString();
        }

        public const string PropertyDspParameter = "DspParameter";

        static BaseModulizerControl()
        {
            DefinedProperties.IgnoreProperty(typeof(BaseModulizerControl), BaseObject.PropertyRotation);
            DefinedProperties.IgnoreProperty(typeof(BaseModulizerControl), BaseObject.PropertyTagName);
            DefinedProperties.IgnoreProperty(typeof(BaseModulizerControl), BaseObject.PropertyVisible);
            DefinedProperties.IgnoreProperty(typeof(BaseModulizerControl), Panel.PropertyMaxSize);
            DefinedProperties.IgnoreProperty(typeof(BaseModulizerControl), Panel.PropertyMinSize);
            DefinedProperties.IgnoreProperty(typeof(BaseModulizerControl), Panel.PropertyOverlayTexture);
            DefinedProperties.IgnoreProperty(typeof(BaseModulizerControl), Panel.PropertyOverlayTextureColor);

            DefinedProperties.AddProperty(PropertyDspParameter, new EntityInteger<BaseModulizerControl>(BaseObject_Set_Dimensionprocent, BaseObject_Get_Dimensionprocent));
        }

        static void BaseObject_Set_Dimensionprocent(BaseModulizerControl obj, int value)
        {
            if (obj.mModule == null)
            {
                obj.mReadyParameterIndex = value;
            }
            else
            {
                System.Collections.Generic.IList<ParameterProperties> properties = GroupModule.GetVisibleProperties(obj.mModule);

                ParameterProperties parameter = properties[value];

                obj.SetParameter(parameter, obj.mControlledBy, obj.mModule);
            }
        }

        static int BaseObject_Get_Dimensionprocent(BaseModulizerControl obj)
        {
            if (obj.mReadyParameterIndex > -1)
            {
                return obj.mReadyParameterIndex;
            }
            else if(obj.mModule == null)
            {
                return -1;
            }
            else
            {
                System.Collections.Generic.IList<ParameterProperties> properties = GroupModule.GetVisibleProperties(obj.mModule);

                int index = properties.IndexOf(obj.mParameter);

                return index;
            }
        }
    }
}
